<template>
    <label>
        <input type="file" style="display: none" @change="_onChange" ref="fileinput" v-if="reset" accept="image/jpeg,image/jpg,image/png"/>
        <slot></slot>
    </label>
</template>
<script>
    import urljoin from 'url-join'
    import ImageCompressor from 'image-compressor.js';

    const MAX_SIZE = 1048576
    export default {
        props: {
            url: {
                type: String,
                default: urljoin(baseURL, 'wx/upload/img')
            },
            // 文件大小限制 字节
            fileSizeLimit: Number,
            // 文件个数限制
            fileNumLimit: Number,

            // 压缩后最大 字节
            maxSize: {
                type: Number,
                default: MAX_SIZE
            }
        },
        data() {
            return {
                images: [],
                reset: true,
                loading: false
            }
        },
        computed: {
            names() {
                return this.images.map(x => x.file.name)
            }
        },
        methods: {
            onAddFile() {
                this.$refs.fileinput.click()
            },
            // 选择文件
            async _onChange() {
                let files = Array.from(this.$refs.fileinput.files)
                files = this._fileNumLimit(files) // 删除超出文件
                files = files.filter(x => this._noRepeat(x) && this._fileSizeLimit(x))
                files = files.map(file => new Promise((resolve, reject) => {
                    console.log('源文件', file.name, Number(file.size / 1024 / 1024).toFixed(2))
                    const quality = this.maxSize / file.size
                    if (quality >= 1) {
                        resolve(file)
                        return
                    }
                    new ImageCompressor(file, {
                        quality,
                        success: result => {
                            resolve(result)
                        },
                        error: error => reject(error),
                    })
                }))
                this.$emit('compress', true)
                this.loading = true
                files = await Promise.all(files)
                this.loading = false
                this.$emit('compress', false)
                this._preview(files)
                this._resizeInput()
            },
            onDel(index) {
                this.images.splice(index, 1)
            },
            // 重置 input 文件选项
            async _resizeInput() {
                this.reset = false
                await this.$nextTick()
                this.reset = true
            },
            // 图片预览
            _preview(files) {
                let count = 0
                files.forEach(file => {
                    const reader = new FileReader()
                    reader.readAsDataURL(file)
                    reader.onload = async result => {
                        const image = {
                            file: file,
                            src: result.target.result,
                            progress: 0,
                            state: null
                        }
                        this.images.push(image)
                        this.$emit('images', this.images)
                        await this.$nextTick()
                        new Upload(this.url, image).start(() => this.$emit('input', this.images.map(({cloud}) => cloud))) // 上传成功，并触发返回 “云图片地址” 事件
                    }
                })
            },

            // 上传文件
            _upload() {

            },
            // 文件去重
            _noRepeat({name}) {
                return !this.names.includes(name)
            },
            // 文件超出大小过滤
            _fileSizeLimit({size}) {
                if (this.fileSizeLimit) {
                    const result = size < this.fileSizeLimit
                    result || this.$emit('fileSizeLimit', this.$data)
                    return result
                }
                return true
            },

            // 文件数量限制
            _fileNumLimit(files) {
                if (this.fileNumLimit > 0) {
                    // 如果限制一张图片，则替换图片
                    if (this.fileNumLimit == 1) {
                        this.images = []
                        return files
                    }
                    this.$emit('fileSizeLimit', this.$data)
                    return files.slice(0, Math.max(this.fileNumLimit - this.images.length, 0))
                }
                return files
            }
        },
        components: {}
    }

    class Upload {
        constructor(url, image) {
            this.image = image
            const xhr = this.xhr = new XMLHttpRequest();  // XMLHttpRequest 对象
            xhr.open("post", url, true); //post方式，url为服务器请求地址，true 该参数规定请求是否异步处理。
            xhr.onload = this._success.bind(this)
            xhr.onerror = this._error.bind(this)
            xhr.upload.onprogress = this._progress.bind(this)
            xhr.upload.onloadstart = this._loadstart.bind(this)
        }

        start(callback) {
            this.callback = callback
            const form = new FormData(); // FormData 对象
            form.append("file", this.image.file, this.image.file.name)
            console.log('压缩后', this.image.file.name, Number(this.image.file.size / 1024 / 1024).toFixed(2))
            this.xhr.send(form); //开始上传，发送form数据
        }

        _success({target}) {
            var data = JSON.parse(target.responseText)
            if (data.code == 200) {
                this.image.progress = 1
                this.image.state = true
                this.image.cloud = data.msg
                this.callback(data.msg)
            }
        }

        _error() {
            this.image.state = false
        }

        _progress({total, loaded, lengthComputable}) {
            // event.total是需要传输的总字节，event.loaded是已经传输的字节。如果event.lengthComputable不为真，则event.total等于0
            if (lengthComputable) {
                this.image.progress = loaded / total
            }
        }

        _loadstart() {
        }
    }
</script>
<style type="text/scss" lang="scss" scoped>
    .box {
        margin-top: 20px;
        .item {
            margin-right: 10px;
        }
    }
</style>
